package com.zhss.eshop.commodity.service.Impl;

import com.zhss.eshop.commodity.domain.dto.*;
import com.zhss.eshop.commodity.domain.model.*;
import com.zhss.eshop.commodity.mapper.*;
import com.zhss.eshop.commodity.service.CommodityCategoryService;
import com.zhss.eshop.commodity.service.Impl.operation.Category;
import com.zhss.eshop.commodity.service.Impl.operation.CategoryOperation;
import com.zhss.eshop.commodity.service.Impl.operation.RelatedCheckCategoryOperation;
import com.zhss.eshop.commodity.service.Impl.operation.RemoveCategoryOperation;
import com.zhss.eshop.common.bean.SpringApplicationContext;
import com.zhss.eshop.common.util.DateProvider;
import com.zhss.eshop.common.util.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

@Service
public class CommodityCategoryServiceImpl implements CommodityCategoryService{

    @Resource
    private CommodityCategoryMapper commodityCategoryMapper;
    /**
     * 日期辅助组件
     */
    @Autowired
    private DateProvider dateProvider;
    /**
     * 类目属性关系dao组件
     */
    @Autowired
    private CommodityCategoryPropertyRelationshipMapper categoryPropertyRelationDAO;
    /**
     * 属性分组dao组件
     */
    @Autowired
    private CommodityPropertyGroupMapper propertyGroupDAO;
    /**
     * 属性分组与属性关系dao组件
     */
    @Autowired
    private CommodityPropertyGroupRelationshipMapper propertyGroupRelationDAO;
    /**
     * 属性管理模块DAO组件
     */
    @Autowired
    private CommodityPropertyMapper propertyDAO;
    /**
     * Spring容器组件
     */
    @Autowired
    private SpringApplicationContext context;

    @Override
    public int deleteByPrimaryKey(Long id) {
        return commodityCategoryMapper.deleteByPrimaryKey(id);
    }

    @Override
    public Boolean insertSelective(CommodityCategoryDTO category) throws Exception {
        saveCategory(category);
        saveCategoryPropertyRelations(category);
        savePropertyGroup(category);
        return true;
    }

    /**
     * 保存类目的基本信息
     * @param category 类目
     * @throws Exception
     */
    private void saveCategory(CommodityCategoryDTO category) throws Exception {
        category.setGmtCreate(dateProvider.getCurrentTime());
        category.setGmtModified(dateProvider.getCurrentTime());
        Long categoryId = commodityCategoryMapper.insertSelective(category.clone(CommodityCategory.class));
        category.setId(categoryId);
    }
    /**
     * 保存类目与属性之间的关联关系
     * @param category 类目
     */
    private void saveCategoryPropertyRelations(CommodityCategoryDTO category) throws Exception {
        if(category.getPropertyRelations() == null ||
                category.getPropertyRelations().size() == 0) {
            return;
        }

        for(CommodityCategoryPropertyRelationshipDTO relation : category.getPropertyRelations()) {
            relation.setCategoryId(category.getId());
            relation.setGmtCreate(dateProvider.getCurrentTime());
            relation.setGmtModified(dateProvider.getCurrentTime());

            categoryPropertyRelationDAO.insertSelective(relation.clone(
                    CommodityCategoryPropertyRelationship.class));
        }
    }
    /**
     * 保存属性分组
     * @param category 类目
     * @throws Exception
     */
    private void savePropertyGroup(CommodityCategoryDTO category) throws Exception {
        if(category.getPropertyGroups() == null ||
                category.getPropertyGroups().size() == 0) {
            return;
        }

        for(CommodityPropertyGroupDTO group : category.getPropertyGroups()) {
            group.setCategoryId(category.getId());
            group.setGmtCreate(dateProvider.getCurrentTime());
            group.setGmtModified(dateProvider.getCurrentTime());

            Long groupId = propertyGroupDAO.insertSelective(group.clone(CommodityPropertyGroup.class));
            group.setId(groupId);

            savePropertyGroupRelations(group);
        }
    }
    /**
     * 保存属性分组与属性的关联关系
     * @param group 属性分组
     * @throws Exception
     */
    private void savePropertyGroupRelations(CommodityPropertyGroupDTO group) throws Exception {
        if(group.getRelations() == null || group.getRelations().size() == 0) {
            return;
        }

        for(CommodityPropertyGroupRelationshipDTO relation : group.getRelations()) {
            relation.setPropertyGroupId(group.getId());
            relation.setGmtCreate(dateProvider.getCurrentTime());
            relation.setGmtModified(dateProvider.getCurrentTime());

            propertyGroupRelationDAO.insertSelective(relation.clone(
                    CommodityPropertyGroupRelationship.class));
        }
    }

    @Override
    public CommodityCategory selectByPrimaryKey(Long id) {
        return commodityCategoryMapper.selectByPrimaryKey(id);
    }

    @Override
    public int updateByPrimaryKeySelective(CommodityCategory record) {
        return commodityCategoryMapper.updateByPrimaryKeySelective(record);
    }

    /**
     * 查询根类目
     * @return 根类目集合
     */
    @Override
    public List<CommodityCategory> listRoots() throws Exception {
        return commodityCategoryMapper.listRoots();
    }
    /**
     * 查询子类目
     * @param id 父类目id
     * @return 子类目集合
     */
    @Override
    public List<CommodityCategory> listChildren(Long id) throws Exception {
        return commodityCategoryMapper.listChildren(id);
    }

    /**
     * 根据id查询类目
     * @param id 类目id
     * @return 类目
     */
    @Override
    public CommodityCategoryDTO getById(Long id) throws Exception {
        // 查询类目基本信息
        CommodityCategoryDTO category = commodityCategoryMapper.selectByPrimaryKey(id).clone(CommodityCategoryDTO.class);

        // 查询类目与属性的关联关系
        List<CommodityCategoryPropertyRelationship> relations =
                categoryPropertyRelationDAO.listByCategoryId(id);
        category.setPropertyRelations(ObjectUtils.convertList(relations,
                CommodityCategoryPropertyRelationshipDTO.class));

        // 查询类目关联的属性
        List<CommodityProperty> properties = new ArrayList<CommodityProperty>();
        for(CommodityCategoryPropertyRelationship relation : relations) {
            properties.add(propertyDAO.selectByPrimaryKey(relation.getPropertyId()));
        }
        category.setProperties(ObjectUtils.convertList(properties, CommodityPropertyDTO.class));

        // 查询类目关联的属性分组
        List<CommodityPropertyGroupDTO> propertyGroups = getPropertyGroupsByCategoryId(id);
        category.setPropertyGroups(propertyGroups);

        return category;
    }

    /**
     * 根据类目id查询属性分组
     * @param categoryId 类目id
     * @return 属性分组
     * @throws Exception
     */
    private List<CommodityPropertyGroupDTO> getPropertyGroupsByCategoryId(
            Long categoryId) throws Exception {
        List<CommodityPropertyGroupDTO> resultPropertyGroups = new ArrayList<CommodityPropertyGroupDTO>();

        // 查询类目关联的属性分组
        List<CommodityPropertyGroup> propertyGroups = propertyGroupDAO.listByCategoryId(categoryId);

        // 查询属性分组与属性的关联关系，以及属性分组关联的属性
        for(CommodityPropertyGroup propertyGroup : propertyGroups) {
            CommodityPropertyGroupDTO resultPropertyGroup = propertyGroup.clone(CommodityPropertyGroupDTO.class);

            List<CommodityPropertyGroupRelationship> relations = propertyGroupRelationDAO
                    .listByPropertyGroupId(propertyGroup.getId());
            resultPropertyGroup.setRelations(ObjectUtils.convertList(relations,
                    CommodityPropertyGroupRelationshipDTO.class));

            List<CommodityPropertyDTO> properties = new ArrayList<CommodityPropertyDTO>();
            for(CommodityPropertyGroupRelationship relation : relations) {
                properties.add(selectByPrimaryKey(relation.getPropertyId()).clone(CommodityPropertyDTO.class));
            }
            resultPropertyGroup.setProperties(properties);

            resultPropertyGroups.add(resultPropertyGroup);
        }

        return resultPropertyGroups;
    }

    /**
     * 删除类目
     * @param id 类目id
     * @throws Exception
     */
    @Override
    public Boolean remove(Long id) throws Exception {
        Category category = new Category(id);

        CategoryOperation<Boolean> relatedCheckOperation = context.getBean(
                RelatedCheckCategoryOperation.class);
        Boolean result = category.execute(relatedCheckOperation);

        if(result) {
            return false;
        }

        CategoryOperation<Boolean> removeOperation =
                context.getBean(RemoveCategoryOperation.class);
        return category.execute(removeOperation);
    }

}
